/*******************************************************************************
 * Copyright (c) 2010 Mikhail Garber.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser Public License (LGPL)
 * which accompanies this distribution
 * 
 * Contributors:
 *     Mikhail Garber - initial API and implementation
 ******************************************************************************/
package plumber;

import plumber.annotations.Outcome;
import plumber.annotations.Plumber;
import plumber.annotations.PlumberFlow;

/**
 * Test component which methods are used as Steps in test workflows.
 * The following work flows are defined in this class:
 * "testflow": checkEven-> if even, double the value, if not, triple it
 * "testThrow" : react on Step throwing an Exception
 * "testTooLong" : test step execution taking longer than allowed
 * 
 * @author mgarber
 *
 */
public class AnnotatedSteps {

	
	
	/**
	 * define first step in "testflow", define two outcomes based on return value of step
	 * @param context
	 * @return
	 */
	@PlumberFlow(flow = "testflow", step = "CheckEven", firstStep = true,
			outcomes = {
			@Outcome(nextStep = "Triple", ifValue = "false"),
			@Outcome(nextStep = "Double", ifValue = "true")
			})
	public boolean isEven(TestContext context) {
		return (context.getValue() % 2 == 0);
	}
	
	/**
	 * a step in "testflow", doubles the value passe in via context
	 * (on very first execution, throws runtime exception to test retry logic
	 * "flow2" workflow is a dummy, added to test definition of a Step participating
	 * in more than one flow
	 * @param context
	 */
	@Plumber(flows = {
	@PlumberFlow(flow = "testflow", step = "Double"),
	@PlumberFlow(flow = "flow2", step = "d", firstStep = true)
	})
	public void timesTwo(TestContext context) {
		if(context.getRetryCount() == 1)
			throw new RuntimeException("testing retry");
		context.setValue(context.getValue() * 2);
	}
	
	/**
	 * step in "testflow". Triples the value
	 * @param context
	 */
	@PlumberFlow(flow = "testflow", step = "Triple")
	public void timesThree(TestContext context) {
		context.setValue(context.getValue() * 3);
	}
	
	/**
	 * step in "testThrow". looks at string value stored in context and
	 * interprets it as a class of exception to be thrown.
	 * @param context
	 * @throws Exception
	 * @throws IllegalAccessException
	 * @throws ClassNotFoundException
	 */
	@PlumberFlow(flow = "testThrow", step = "1", firstStep = true, maxRetryCount = 2,
			outcomes = {
			@Outcome(ifExceptionClassName = "java.lang.IllegalStateException", nextStep = "2")
	})
	public void throwSomething(TestContext context) throws Exception, IllegalAccessException, ClassNotFoundException {
		String className = context.getSvalue();
		Object o = Class.forName(className).newInstance();
		throw (Exception)o;
	}
	
	/**
	 * step in "testThrow". Sets integer value in context to 27
	 * @param context
	 */
	@PlumberFlow(flow = "testThrow", step = "2")
	public void make27(TestContext context) {
		context.setValue(27);
	}
	
	/**
	 * step in "testTooLong". Configured to run for max of 2 seconds and runs longer than that.
	 * @param context
	 * @return
	 * @throws InterruptedException
	 */
	@PlumberFlow(flow = "testTooLong", step = "1", firstStep = true, maxRetryCount = 2, maxRuntimeSeconds = 2)
	public String tooLong(TestContext context) throws InterruptedException {
		Thread.sleep(14000);
		return "hi";
	}
}
